package com.wawu.ioc;

import com.wawu.annotation.IOC.Autowired;
import com.wawu.annotation.IOC.component.Component;
import com.wawu.annotation.IOC.component.RestController;
import com.wawu.util.AnnotationUtils;
import lombok.Getter;
import org.reflections.Reflections;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;


//这里只整了单例模式
/*
gpt生成出来一直跟我的需求有点偏差，不是我想要这里只能自己写了
 */
//后续经过测试
//        Reflections reflections = new Reflections(basePackage);
//        Set<Class<?>> annotations = reflections.getTypesAnnotatedWith(Component.class);
//会搜索包括类和注解但是并不会过滤出嵌套注解(放在注解上的注解)
public class ApplicationContext {//有点类型工厂诶

    private Set<Class<? extends Annotation>> registerComponentAnnotations = new HashSet<>();//这里存放被@Component修饰的注解，其实也不算特别有必要
    //注册后的实例容器，这里直接默认单例了
    private Map<Class<?>, Object> beanMap = new HashMap<>();  // 存储类和其实例
    @Getter
    private Set<Class<?>> restControllerClazzes = new HashSet<>();//单独再拿出被@RestController修饰的类，后续还需要注册路由


    public ApplicationContext(String basePackage,String baseAnnotationPackage) {
        // 1. 获取所有自定义注解，并筛选出需要注册的注解
        scanForRegisterAnnotations(baseAnnotationPackage);
        System.out.println("@Component相关注解:"+registerComponentAnnotations);
        // 2. 扫描并注册组件类
        scanAndRegisterComponents(basePackage);
        // 3. 执行依赖注入
        injectDependencies();
    }

    // 获取所有自定义注解，并筛选出标记了 @Component 的注解
        //TODO 这里只扫扫描了所有带@Component这样其实并没有实现扫描所有注解，感觉用这个框架可能做不到
    private void scanForRegisterAnnotations(String basePackage) {
        registerComponentAnnotations.add(Component.class);

        Reflections reflections = new Reflections(basePackage);
        Set<Class<?>> annotations = reflections.getTypesAnnotatedWith(Component.class);
//        Set<Class<?>> annotations = reflections.getTypesAnnotatedWith(Annotation.class);
        System.out.println(annotations);
        for (Class<?> annotation : annotations) {
            if(annotation.isAnnotation()){
                if(AnnotationUtils.isAnnotationPresent(annotation,Component.class,true)){
                    registerComponentAnnotations.add((Class<? extends Annotation>) annotation);
                }
            }
        }
    }



    private void scanAndRegisterComponents(String basePackage) {
        Reflections reflections = new Reflections(basePackage);
        //获取所有被@Component修饰的类(需要包括嵌套的)
        System.out.println("开始找@Component相关类：");
        for(Class<? extends Annotation> registerComponentAnnotation:registerComponentAnnotations){
            Set<Class<?>> componentWithComponentAnnotated = reflections.getTypesAnnotatedWith(registerComponentAnnotation);//注意不会识别嵌套注解
            System.out.println(registerComponentAnnotation.getName()+":"+componentWithComponentAnnotated);
            for (Class<?> clazz : componentWithComponentAnnotated) {
                //如果为一个普通类，则进行注册实例化
                if(!clazz.isInterface() && !clazz.isEnum() && !clazz.isPrimitive() && !clazz.isArray()){
                    try {
                        Object bean = clazz.getDeclaredConstructor().newInstance();
                        beanMap.put(clazz, bean);  // 将类及其实例包装对象加入beanMap
                    }catch (Exception e) {
                        e.printStackTrace();
                    }
                    //获取被@RestController修饰的类，后需要注册路由
                    if(clazz.isAnnotationPresent(RestController.class)){
                        restControllerClazzes.add(clazz);
                    }
                }
            }
        }

    }

    //执行依赖注入
    private void injectDependencies() {
        // 遍历所有注册的 Bean 类
        for (Map.Entry<Class<?>, Object> entry : beanMap.entrySet()) {
            Object bean = entry.getValue();
            Class<?> clazz = entry.getKey();

            // 获取所有字段，检查是否有 @Autowired 注解
            for (Field field : clazz.getDeclaredFields()) {
                if (field.isAnnotationPresent(Autowired.class)) {
                    // 获取字段的类型
                    Class<?> fieldType = field.getType();

                    // 如果字段类型是接口，则需要根据接口类型获取实现类
                    if (fieldType.isInterface()) {
                        // 获取所有实现该接口的类
                        Set<Class<?>> implementors = getImplementors(fieldType);
                        if (implementors.size() == 1) {
                            // 如果只找到一个实现，注入这个实现
                            try {
                                //这里依然是从bean，而不是新建了
//                                Object dependency = implementors.iterator().next().getDeclaredConstructor().newInstance();
                                Object dependency=beanMap.get(implementors.iterator().next());//TODO 探究：这里可以看看为什么不需要.getClass()
                                field.setAccessible(true);
                                field.set(bean, dependency);
                            } catch (Exception e) {
                                e.printStackTrace();
                            }
                        } else {
                            System.err.println("找到多个实现或者没有实现接口的类: " + fieldType.getName());
                        }
                    } else {
                        // 如果字段类型不是接口，直接从 beanMap 获取
                        Object dependency = beanMap.get(fieldType);
                        if (dependency != null) {
                            try {
                                field.setAccessible(true);
                                field.set(bean, dependency);
                            } catch (IllegalAccessException e) {
                                e.printStackTrace();
                            }
                        } else {
                            // 如果找不到匹配的依赖
                            System.err.println("无法注入依赖: " + fieldType.getName());
                        }
                    }
                }
            }
        }
    }

    // 获取接口类型的所有实现类
    private Set<Class<?>> getImplementors(Class<?> interfaceType) {
        Set<Class<?>> implementors = new HashSet<>();
        // 扫描所有已注册的 Bean，查找实现了该接口的类
        for (Class<?> clazz : beanMap.keySet()) {
            if (interfaceType.isAssignableFrom(clazz) && !clazz.equals(interfaceType)) {
                implementors.add(clazz);
            }
        }
        return implementors;
    }



    //获取响应的bean对象
    public <T> T getBean(Class<T> clazz) {
        // 从 beanMap 中查找指定类的实例
        Object bean = beanMap.get(clazz);

        // 如果找不到该类型的 Bean，可以考虑抛出异常或返回 null
        if (bean == null) {
            throw new IllegalArgumentException("No bean found for class: " + clazz.getName());
        }

        return clazz.cast(bean); // 返回转换为指定类型的 bean
    }
}
